import type { RouteRecordRaw, RouteComponent } from 'vue-router'
import { LAYOUT_ROUTER_NAME, ERROR_ROUTER_NAME } from '@/const/router'
import localMenus from '@/const/local-menus'
import useAuthStore from '@/store/modules/auth'
import type { RouteItem } from '../interface'
import type { ComponentType } from '../types'
import router from '../index'

const modules = import.meta.glob('@/views/**/*.vue')

/**
 * @description 动态加载组件
 * @param {string} component 组件路径
 * @returns {function} 动态加载的组件
 */
export function lazyLoadComponent(component: ComponentType): () => Promise<RouteComponent> {
  if (component) {
    for (const path in modules) {
      const dir = path.split('views')[1]?.split('.vue')[0]
      if (dir && (dir === component || dir === component + '/index')) {
        // 使用非空断言
        return modules[path]! as () => Promise<{ default: any }>
      }
    }
  }

  return () => import('@/views/exception/empty.vue')
}

/**
 * @description 路由树过滤
 * @param {any[]} tree 路由树
 * @param {function} fn 过滤函数
 * @returns {any[]} 过滤后的路由树
 */
export function treeFilter(tree: any[], fn: (node: any) => boolean): any[] {
  return tree
    .map((node) => ({ ...node }))
    .filter((node) => {
      node.children = node.children && treeFilter(node.children, fn)
      return fn(node) || (node.children && node.children.length)
    })
}

/**
 * @description 路由扁平化
 * @param {RouteRecordRaw[]} routes 路由树
 * @param {RouteItem[]} breadcrumb 面包屑
 * @returns {RouteRecordRaw[]} 扁平化后的路由
 */
export function flatRoutes(routes: RouteRecordRaw[], breadcrumb: RouteRecordRaw[] = []) {
  let result: RouteRecordRaw[] = []
  routes.forEach((route: RouteRecordRaw) => {
    const tmp = { ...route, meta: route.meta || {} }
    if (tmp.children) {
      let childrenBreadcrumb = [...breadcrumb]
      childrenBreadcrumb.push(route as RouteRecordRaw)
      let tmpRoute = { ...route, meta: route.meta || {} }
      tmpRoute.meta.breadcrumb = childrenBreadcrumb
      delete tmpRoute.children
      result.push(tmpRoute)
      let childrenRoutes = flatRoutes(tmp.children, childrenBreadcrumb)
      childrenRoutes.map((item) => result.push(item))
    } else {
      let tmpBreadcrumb = [...breadcrumb]
      tmpBreadcrumb.push(tmp)
      tmp.meta.breadcrumb = tmpBreadcrumb
      result.push(tmp)
    }
  })

  return result
}

/**
 * @description 获取动态路由
 * @returns {RouteRecordRaw[]} 动态路由
 */
export async function getDynamicMenus() {
  const userMenu = treeFilter([], (node) => {
    return node.meta.role
      ? node.meta.role.filter((item: string) => ([] as string[]).indexOf(item) > -1).length > 0
      : true
  })
  const menus = [...userMenu, ...localMenus]

  return menus
}

/**
 * @description 生成动态路由
 * @param {RouteItem[]} routes 路由树
 * @returns {RouteItem[]} 动态路由
 */
export function generateRouter(routes: RouteItem[]): RouteRecordRaw[] {
  const result: RouteRecordRaw[] = []
  routes.forEach((item) => {
    const route: RouteRecordRaw = {
      path: item.path,
      name: item.name,
      meta: item.meta || {},
      redirect: item.redirect || '',
      children: item.children ? generateRouter(item.children) : undefined,
      component: item.component ? lazyLoadComponent(item.component) : undefined,
    } as RouteRecordRaw

    result.push(route)
  })

  return result
}

// 初始化动态路由
export async function initDynamicRouter() {
  try {
    const authStore = useAuthStore()
    const menus = await authStore.getAuthMenuList()
    let dynamicRouter = generateRouter(menus)
    dynamicRouter = flatRoutes(dynamicRouter)
    dynamicRouter.forEach((item) => router.addRoute(LAYOUT_ROUTER_NAME, item))
  } catch (error) {
    router.replace(ERROR_ROUTER_NAME)
  }
}
